import { http } from "@/utils/http";
import type { EventSourceMessage } from "@microsoft/fetch-event-source";
import { EventType, type ServerSentEvent } from "@/types/sse.types";
import { URL_PREFIX } from "./constants";

/**
 * Callback types for different event types
 */
export interface ServerSentEventCallbacks {
  onError?: (error: Error) => void;
  onOpen?: (response: Response) => void;
  onClose?: () => void;
  onEvent?: (event: ServerSentEvent) => void;
}

/**
 * Configuration for the SSE connection
 */
export interface EventStreamConfig {
  /** Additional query parameters to include in the request */
  params?: Record<string, any>;
  /** Heartbeat configuration */
  heartbeat?: {
    /** Timeout in milliseconds after which to close the connection if no events received */
    timeoutMs?: number;
    /** How often to check for timeout (ms) */
    checkIntervalMs?: number;
  };
}

/**
 * Creates an SSE connection to event stream
 *
 * @param callbacks - Callback functions for different event types
 * @param config - Configuration options for the connection
 * @returns An object with a close method to terminate the connection
 */
export function createEventStream(
  callbacks: ServerSentEventCallbacks,
  config?: EventStreamConfig
) {
  const url = `${URL_PREFIX}/events/stream`;

  // Create the connection
  return http.createSSEConnection(
    url,
    {
      onOpen: callbacks.onOpen,
      onClose: callbacks.onClose,
      onError: callbacks.onError,
      onMessage: (message: EventSourceMessage) => {
        try {
          // Skip keep-alive messages or empty messages
          if (!message.data || message.data === "") {
            return;
          }

          // Skip unknown event types
          if (!Object.values(EventType).includes(message.event as EventType)) {
            console.warn("Unknown event type:", message.event);
            return;
          }

          // Skip event without eventID
          if (!message.id) {
            console.warn("Event without eventID:", message);
            return;
          }

          const event = {
            event_id: message.id,
            event_type: message.event as EventType,
            data: JSON.parse(message.data)
          } as ServerSentEvent;

          // If there's an onEvent callback, pass the full event to it
          if (callbacks.onEvent) {
            callbacks.onEvent(event);
          } else {
            // Log a warning if no event handler is provided
            console.warn("No event handler provided for event:", event);
          }
        } catch (error) {
          console.error("Error processing SSE message:", error);
          if (callbacks.onError) {
            callbacks.onError(
              error instanceof Error ? error : new Error(String(error))
            );
          }
        }
      },
      // Pass heartbeat config to the PureHttp class
      heartbeat: config?.heartbeat
    },
    config?.params
  );
}
